package com.ccrfid.rmc6.appconfig.filter;

import org.glassfish.jersey.message.MessageUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import javax.annotation.Priority;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.*;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.io.OutputStream;

@PreMatching
@Provider
@Priority(Priorities.USER)
public class CustomServerLoggingFilter extends CustomLoggingInterceptor
        implements ContainerRequestFilter, ContainerResponseFilter {
    private static final Logger logger = LoggerFactory.getLogger(CustomServerLoggingFilter.class);

    public CustomServerLoggingFilter() {
        super(logger, 16 * 1024);
    }

    private static boolean notIgnore(ContainerRequestContext context) {
        String uri = context.getUriInfo().getPath();
        return !uri.contains("/real-position/");
    }

    @Override
    public void filter(ContainerRequestContext context) throws IOException {
        if (logger.isDebugEnabled() && notIgnore(context)) {
            MDC.put("starttime", String.valueOf(System.currentTimeMillis()));
            final long id = logSequence.incrementAndGet();
            context.setProperty(LOGGING_ID_PROPERTY, id);
            final StringBuilder b = new StringBuilder();

            printRequestLine(b, "Server has received a request", id, context.getMethod(), context.getUriInfo().getRequestUri());
            printPrefixedHeaders(b, id, REQUEST_PREFIX, context.getHeaders());
            if (context.hasEntity() && printable(context.getMediaType())) {
                context.setEntityStream(logInboundEntity(b, context.getEntityStream(), MessageUtils.getCharset(context.getMediaType())));
            }
            log(b);
        }
    }

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
        if (logger.isDebugEnabled() && notIgnore(requestContext)) {
            final Object requestId = requestContext.getProperty(LOGGING_ID_PROPERTY);
            final long id = (requestId != null ? (Long) requestId : logSequence.incrementAndGet());

            final StringBuilder b = new StringBuilder();

            printResponseLine(b, "Server responded with a response", id, responseContext.getStatus());
            printPrefixedHeaders(b, id, RESPONSE_PREFIX, responseContext.getStringHeaders());
            String timeStr = MDC.get("starttime");
            if (timeStr != null && timeStr.length() > 0) {
                long starttime = Long.parseLong(timeStr);
                long executionTime = System.currentTimeMillis() - starttime;
                printExecutionTime(b, id, executionTime);
            }
            MDC.clear();

            if (responseContext.hasEntity() && printable(responseContext.getMediaType())) {
                final OutputStream stream = new LoggingStream(b, responseContext.getEntityStream());
                responseContext.setEntityStream(stream);
                requestContext.setProperty(ENTITY_LOGGER_PROPERTY, stream);
                // not calling log(b) here - it will be called by the interceptor
            } else {
                log(b);
            }
        }
    }
}
